package com.example.sihookuiklydemo.ble

import com.tencent.kuikly.core.annotations.Page
import com.tencent.kuikly.core.base.Attr
import com.tencent.kuikly.core.base.ComposeView
import com.tencent.kuikly.core.log.KLog
import com.tencent.kuikly.core.module.NotifyModule
import com.tencent.kuikly.core.nvi.serialization.json.JSONArray
import com.tencent.kuikly.core.nvi.serialization.json.JSONObject
import com.tencent.kuikly.core.pager.PageData
import com.tencent.kuikly.core.pager.PageData.Companion.PLATFORM_ANDROID
import com.tencent.kuikly.core.pager.Pager
import com.tencent.kuikly.core.views.DivAttr
import kotlin.math.pow

const val CMD_READ = 0X10
const val CMD_WRITE = 0X20
const val CMD_FILE = 0X50
const val CMD_END = 0xbb
const val SlaveAddress = 0X01
const val DATA_Start_POSITION = 10
const val DATA_Status_POSITION = 12
const val DATA_RECEVIER_POSITION = 13

const val ADDRESS_DESK_lOCK = 0XD400
const val ADDRESS_DESK_lOCK_GET = 0XD402
const val ADDRESS_DESK_LANGUAGE = 0XD404
const val ADDRESS_DESK_LANGUAGE_GET = 0XD406
const val ADDRESS_DESK_TIMER_ENABLE = 0XD408
const val ADDRESS_DESK_TIMER_ENABLE_GET = 0XD40A
const val ADDRESS_DESK_TIMER = 0XD40C
const val ADDRESS_DESK_TIMER_GET = 0XD40E
const val ADDRESS_DESK_UNITCHANGE = 0XD410
const val ADDRESS_DESK_UNIT_GET = 0XD412
const val ADDRESS_DESK_HEIGHT = 0XD414
const val ADDRESS_DESK_HEIGHT_GET = 0XD416
const val ADDRESS_DESK_MODE = 0XD418

const val ADDRESS_DESK_MODE_HEIGHT0 = 0XD426
const val ADDRESS_DESK_MODE_HEIGHT1 = 0XD428
const val ADDRESS_DESK_MODE_HEIGHT2 = 0XD42A
const val ADDRESS_DESK_MODE_GET = 0XD42C
fun getAutoStandHeight(userHeight: Int): Int {
    return when (userHeight) {
        in 0..145 -> 84
        in 146..148 -> {
            var offset = userHeight - 146
            85 + offset
        }

        149 -> 87
        in 150..165 -> {
            var offset = userHeight - 150
            88 + offset
        }

        166 -> 103
        in 167..177 -> {
            var offset = userHeight - 167
            104 + offset
        }

        in 178..190 -> 115
        in 191..196 -> 116
        else -> 117
    }
}

fun getAutoSitHeight(userHeight: Int): Int {
    return when (userHeight) {
        in 0..186 -> 72
        in 187..201 -> {
            var offset = userHeight - 187
            73 + offset / 3
        }

        in 202..203 -> 78
        else -> 79
    }
}

fun readData(addressData: Int): ByteArray {
    return initReadByteArray(addressData, 1)
}

fun getMode(): ByteArray {

    return initReadByteArray(ADDRESS_DESK_MODE_GET, 2)
}

fun changeModeHeight0(height: Int): ByteArray {
    var contentValue = getSingleDataByteArray(height * 10)
    return initWriteByteArray(ADDRESS_DESK_MODE_HEIGHT0, contentValue)
}

fun changeModeHeight1(height: Int): ByteArray {
    var contentValue = getSingleDataByteArray(height * 10)
    return initWriteByteArray(ADDRESS_DESK_MODE_HEIGHT1, contentValue)
}

fun changeModeHeight2(height: Int): ByteArray {
    var contentValue = getSingleDataByteArray(height * 10)
    return initWriteByteArray(ADDRESS_DESK_MODE_HEIGHT2, contentValue)
}

fun enableLock(enableLock: Boolean): ByteArray {
    var data = enableByteArray(enableLock)
    var contentValue = getSingleDataByteArray(data)
    return initWriteByteArray(ADDRESS_DESK_lOCK, contentValue)
}

fun changeLanguage(language: Int): ByteArray {
    var contentValue = getSingleDataByteArray(language)
    return initWriteByteArray(ADDRESS_DESK_LANGUAGE, contentValue)
}

fun enableTimer(enableTimer: Boolean): ByteArray {
    var data = enableByteArray(enableTimer)
    var contentValue = getSingleDataByteArray(data)
    return initWriteByteArray(ADDRESS_DESK_TIMER_ENABLE, contentValue)
}

fun enableByteArray(enable: Boolean): Int {
    return when (enable) {
        true -> 1
        else -> 0
    }
}

fun setTimerDuration(duration: Int): ByteArray {
    var contentValue = getSingleDataByteArray(duration)
    return initWriteByteArray(ADDRESS_DESK_TIMER, contentValue)
}

fun setUnit(unit: Int): ByteArray {
    var contentValue = getSingleDataByteArray(unit)
    return initWriteByteArray(ADDRESS_DESK_UNITCHANGE, contentValue)
}

fun setHeightMode(height: Int): ByteArray {
    var contentValue = getSingleDataByteArray(height)
    return initWriteByteArray(ADDRESS_DESK_HEIGHT, contentValue)
}

fun getSingleDataByteArray(data: Int): ByteArray {
    var contentValue = ByteArray(2)
    contentValue[0] = (data shr 8).toByte()
    contentValue[1] = data.toByte()
    return contentValue
}

fun setMode(standHeight: Int, sitHeight: Int): ByteArray {
    var contentValue = ByteArray(4)
    contentValue[0] = (standHeight shr 8).toByte()
    contentValue[1] = standHeight.toByte()
    contentValue[2] = (sitHeight shr 8).toByte()
    contentValue[3] = sitHeight.toByte()
    return initWriteByteArray(ADDRESS_DESK_MODE, contentValue)
}

private val TAG = "DeskUtils"

/*fun getCurrentDeskModeList(equipmentId: Int): ArrayList<DeskModeItemEntity> {
    var bindDeviceResultBean =
        DbHelper.getInstance().getBindEquipmentInfoDao()?.queryDevice(equipmentId)
    var modeList = ArrayList<DeskModeItemEntity>()
    bindDeviceResultBean?.let {
        modeList = getModeList(it.customDeskModeJson)
    }
    return modeList
}

fun getModeList(

    customDeskModeJson: JsonElement?
): ArrayList<DeskModeItemEntity> {
    var modeList = ArrayList<DeskModeItemEntity>()
    var deskModeList = Gson().fromJson(customDeskModeJson, DeskModeList::class.java)
    if (deskModeList.isNullOrEmpty()) return modeList

    deskModeList?.forEach {
        var type = if (it.isAuto) DeskModeItemEntity.TYPE_Auto else DeskModeItemEntity.TYPE_Diy
        var mode = DeskModeItemEntity(type)
        mode.deskMode = it
        modeList.add(mode)
    }
    modeList.sortByDescending { it.deskMode?.isAuto }
    return modeList
}

fun getSelectedPosition(modeList: ArrayList<DeskModeItemEntity>): Int {
    var selectedPosition = -1
    if(modeList.isNullOrEmpty())return 0
    modeList?.forEach {
        var deskMode = it.deskMode
        if (deskMode!!.isSelected) {
            selectedPosition = modeList.indexOf(it)
        }
    }
    info(TAG, "getSelectedPosition: $selectedPosition")
    if (selectedPosition == -1) {
        selectedPosition = 0
        modeList[0].deskMode?.isSelected = true
    }
    return selectedPosition
}

var maxDeskHeight = 120
var minDeskHeight = 67
fun checkLimitHeight(dataType: Int, currentHeight: Int, activity: BaseActivity<*>) {
    var tipsString = ""
    when (dataType) {
        0 -> {
            if (currentHeight == maxDeskHeight) {
                tipsString = getShowText("desk_max_height_reached",activity)?:"已到达最大高度"
            }
        }
        else -> {
            if (currentHeight == minDeskHeight) {
                tipsString =getShowText("desk_min_height_reached",activity)?:"已到达最小高度"
            }
        }
    }
    if(!TextUtils.isEmpty(tipsString)){
        activity.showTopToast(tipsString)
    }
}*/
fun initReadByteArray(addressData: Int, readLength: Int): ByteArray {
    var sendValue = ByteArray(16)


    //开始地址
    sendValue[DATA_Start_POSITION] = (addressData shr 8).toByte()
    sendValue[DATA_Start_POSITION + 1] = addressData.toByte()
    //读取数据长度，返回的数据字节长度是这个长度*2
    sendValue[DATA_Start_POSITION + 2] = readLength.toByte()
    commData(sendValue, CMD_READ)

    return sendValue


    /*  Log.i(TAG, "initReadByteArray: ${sendValue.toHex()}")*/

}

fun initWriteByteArray(addressData: Int, contentValue: ByteArray): ByteArray {
    var defaultLength = 16;
    var contentLength = contentValue.size
    var writeLength = contentLength / 2;
    var sendValue = ByteArray(defaultLength + contentLength)

    //开始地址
    sendValue[DATA_Start_POSITION] = (addressData shr 8).toByte()
    sendValue[DATA_Start_POSITION + 1] = addressData.toByte()
    //读取数据长度，返回的数据字节长度是这个长度*2
    sendValue[DATA_Start_POSITION + 2] = writeLength.toByte()


    contentValue.copyInto(sendValue, DATA_Start_POSITION + 3, 0, contentLength)


    commData(sendValue, CMD_WRITE)
    KLog.i(TAG, "initWriteByteArray:${sendValue.size} ${sendValue.toHexDString()}")

    return sendValue
}

//内容长度length =value的长度-4
fun commData(sendValue: ByteArray, opType: Int) {


    var valueLength = sendValue.size;
    var cmdHeader = 0xaa
    var encryption = 0

    var length = sendValue.size - 4
    //包头
    sendValue[0] = cmdHeader.toByte()
    //数据长度
    sendValue[1] = (length shr 8).toByte()
    sendValue[2] = length.toByte()
    //从机地址
    sendValue[3] = SlaveAddress.toByte()
    //操作类型
    sendValue[9] = opType.toByte()
    //crc(kotlin的算法会有问题,直接用java算法)
    var crc = crc16Check(sendValue, 1, valueLength - 4)
    sendValue[valueLength - 3] = crc!![0]
    sendValue[valueLength - 2] = crc!![1]
    //包尾
    sendValue[valueLength - 1] = CMD_END.toByte()


}

fun ByteArray.toHexDString(
    separator: String = "",
    prefix: String = " ",
    chunkSize: Int = 0
): String {
    val result = StringBuilder()
    forEachIndexed { index, byte ->
        if (chunkSize > 0 && index % chunkSize == 0 && index != 0) {
            result.append(separator)
        }
        result.append(prefix).append(
            (byte.toInt() and 0xFF).toString(16)
                .padStart(2, '0').uppercase()
        )
    }
    return result.toString()
}


fun crc16Check(data: ByteArray, offset: Int, num: Int): ByteArray {
    val checkSum = ByteArray(2)

    var i = 0
    var j = 0
    var c = 0
    var crc = 0

    crc = 0xffff
    i = offset
    while (i < num + offset) {
        c = data[i].toInt() and 0x00ff
        crc = crc xor c
        j = 0
        while (j < 8) {
            if ((crc and 0x0001) != 0) {
                crc = crc shr 1
                crc = crc xor 0xa001
            } else {
                crc = crc shr 1
            }
            j++
        }
        i++
    }
    checkSum[0] = (crc shr 8).toByte()
    checkSum[1] = crc.toByte()
    return checkSum
}

fun byteToIntValue(value: ByteArray, position: Int): Int {
    var highValue = value[position]
    var lowValue = value[position + 1]
    var intValue = getValue(highValue, 1) + getValue(lowValue, 0)
    return intValue
}

fun getValue(b: Byte, count: Int): Int {
    return ((b.toInt() and 0xff) * 256.0.pow(count.toDouble())).toInt()
}

/**
 * 判断数据类型
 * @param value ByteArray
 * @return Int
 */
fun getDataType(value: ByteArray): Int {
    var type = byteToIntValue(value, DATA_Start_POSITION)

    return type
}

fun sendNotifyList(ctx: ComposeView<*, *>, opName: String, value: JSONArray) {
    ctx.acquireModule<NotifyModule>(NotifyModule.MODULE_NAME).postNotify(
        "BLE_OP_LIST",
        JSONObject().apply {
            put(opName, value)
        })
}

fun getHexData(data: String): ByteArray {
    var length = data.length
    val sendData = ByteArray(length / 2)
    for (i in 0 until length / 2) {
        val input: String = data.substring(i * 2, i * 2 + 2)
        sendData[i] = input.toInt(16).toByte()
    }
    return sendData
}

fun Float.getNewPx(pageData: PageData): Float {
    return this
    /*var jsonObject = pageData.params
    var isPad = jsonObject.optBoolean("isPad")
    var platform = pageData.platform
    return when (platform) {
        PLATFORM_ANDROID -> {
            if (isPad) {
                var height = pageData.activityHeight * pageData.density
                var customSizeInDp = 767f
                var newDensityHeight = height / customSizeInDp
                var heightScale = newDensityHeight / pageData.density
                this * heightScale
            } else {
                var width = pageData.activityWidth * pageData.density
                var designDp = 375f
                var newDensity = width / designDp
                var newDensityDpi = newDensity * 160f

                var scale = newDensity / pageData.density
                this * scale
            }
        }

        else -> this*/
}


fun Pager.getNewFloatPx(floatValue: Float): Float {
    return pagerData.transFloatPx(floatValue)
}

fun Attr.getNewFloatPx(floatValue: Float): Float {
    return pagerData.transFloatPx(floatValue)
}

fun PageData.transFloatPx(floatValue: Float): Float {
    var jsonObject = this.params
    var isPad = jsonObject.optBoolean("isPad")
    var platform = this.platform
    return when (platform) {
        PLATFORM_ANDROID -> {
            floatValue
        }

        else -> floatValue
    }
}